

const babel = require('@babel/core')
const types = require('@babel/types')
const transformEs2015ArrowFunction = require('babel-plugin-transform-es2015-arrow-functions')


// 实现 箭头函数转普通函数 插件
const transformEs2015ArrowFunction2 = {
    visitor: {
        ArrowFunctionExpression(path) {
            const { node } = path
            // console.log(node)
            hoistFunctionEnvironment(path) // 处理this问题
            node.type = 'FunctionDeclaration'
            const body = node.body
            node.body = types.blockStatement([ // 添加return 语句 兼容 (a,b)=>a+b语法糖写法
                types.returnStatement(body)
            ])
        }
    }
}

function hoistFunctionEnvironment(path) {
    // 确定当前箭头函数this指向
    // 原理- 从当前节点向上查找父节点， 查找是函数并且不是箭头函数的 或者是根节点
    const thisEnv = path.findParent(parent => {
        return (parent.isFunction() && !path.isArrowFunctionExpress()) || parent.isProgram()
    })
    let thisBindings = '_this';
    let thisPaths = getThisPaths(path) // 获取使用了this的所有子节点
    if (thisPaths.length) {
        thisEnv.scope.push({
            id: types.identifier(thisBindings), // types生成ast节点 生成一个变量生命 var _this = ？
            init: types.thisExpression() // 变量值 === this
        })
    }

    thisPaths.forEach(thisPath => {
        // this=>_this
        thisPath.replaceWith(types.identifier(thisBindings)) // 将this 全部替换为_this
    })
}

function getThisPaths(path) {
    let thisPaths = []
    path.traverse({// 遍历当前节点
        ThisExpression(thisPath) {  // 记录使用了this的节点
            thisPaths.push(thisPath)
        }
    })
    return thisPaths
}

/**
 使用this时相当于
    var _this = this
    const sum = (a,b)=>{
        console.log(_this)
        return  a+b
    }
 */

// const sourceCode = `
//     const sum = (a,b)=>{
//         console.log(this)
//         return  a+b
//     }
// `

const sourceCode = `
    const sum = (a,b)=>a+b
`

const result = babel.transform(sourceCode, {
    plugins: [transformEs2015ArrowFunction2]
})


console.log(result.code)